#-------------------------------------------
#############  德数WMS  #################
###   email:yueran@pku.edu.org        ###
###   QQ群号：201541335                ###
#-------------------------------------------
import os
from flask import Flask, url_for, redirect, render_template, request, abort
from flask_sqlalchemy import SQLAlchemy
from flask_security import Security, SQLAlchemyUserDatastore, \
    UserMixin, RoleMixin, login_required, current_user
from flask_security.utils import encrypt_password
import flask_admin
from flask_admin.contrib import sqla
from flask_admin import helpers as admin_helpers
from flask_admin import BaseView, expose
from wtforms import PasswordField
from flask_babelex import Babel
# Create Flask application
app = Flask(__name__)
app.config.from_pyfile('config.py')
db = SQLAlchemy(app)

babel = Babel(app)

app.config['BABEL_DEFAULT_LOCALE'] = 'zh_CN'


# Define models
roles_users = db.Table(
    'roles_users',
    db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
    db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
)


class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))

    def __str__(self):
        return self.name


class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(255), nullable=False)
    last_name = db.Column(db.String(255))
    email = db.Column(db.String(255), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

    def __str__(self):
        return self.email


# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)



# Create customized model view class
class MyModelView(sqla.ModelView):

    def is_accessible(self):
        if not current_user.is_active or not current_user.is_authenticated:
            return False

        if current_user.has_role('superuser'):
            return True

        return False

    def _handle_view(self, name, **kwargs):
        """
        Override builtin _handle_view in order to redirect users when a view is not accessible.
        """
        if not self.is_accessible():
            if current_user.is_authenticated:
                # permission denied
                abort(403)
            else:
                # login
                return redirect(url_for('security.login', next=request.url))


    # can_edit = True
    edit_modal = True
    create_modal = True    
    can_export = True
    can_view_details = True
    details_modal = True

class UserView(MyModelView):
    column_labels = dict(   
    email=u'邮件',
    first_name=u'名字',
    last_name=u'姓氏',
    active=u'激活',
    confirmed_at=u'确认日期',
    password=u'密码'
    )
    column_editable_list = ['email', 'first_name', 'last_name']
    column_searchable_list = column_editable_list
    column_exclude_list = ['password']
    column_details_exclude_list = column_exclude_list
    column_filters = column_editable_list
    form_overrides = {
        'password': PasswordField
    }

class Product(db.Model, UserMixin):
    id_Pdt = db.Column(db.Integer, primary_key=True)
    num_Pdt = db.Column(db.String(255),nullable=False)
    product = db.Column(db.String(255), nullable=False)
    location = db.Column(db.String(255), nullable=False)
    total_Pdt = db.Column(db.Integer,nullable=False)
    lock_Pdt = db.Column(db.Integer,nullable=False)
    unsold_Pdt = db.Column(db.Integer,nullable=False)
    loss_Pdt = db.Column(db.Integer,nullable=False)
    indate = db.Column(db.DateTime())

    def __str__(self):
        return self.product
class WHouse(db.Model, UserMixin):
    id_wh = db.Column(db.Integer, primary_key=True)
    num_wh = db.Column(db.String(255),nullable=False)
    location = db.Column(db.String(255), nullable=False)
    total_wh = db.Column(db.Integer,nullable=False)
    lock_wh = db.Column(db.Integer,nullable=False)
    unsold_wh = db.Column(db.Integer,nullable=False)
    loss_wh = db.Column(db.Integer,nullable=False)
    update = db.Column(db.DateTime())

    def __str__(self):
        return self.product

class ProductView(MyModelView):
    
  
    column_labels = dict(   
    num_Pdt=u'商品编号',
    product=u'商品名称',
    location=u'位置',
    total_Pdt=u'总数',
    lock_Pdt=u'锁定数',
    unsold_Pdt=u'待售数',
    loss_Pdt=u'损耗数',
    indate=u'入库时间'
    )
    column_editable_list = ['product', 'location', 'total_Pdt','lock_Pdt','loss_Pdt','indate']
    column_searchable_list = column_editable_list
   
    column_filters = column_editable_list
    form_overrides = {
        'password': PasswordField
    }
class WHouseView(MyModelView):
    
  
    column_labels = dict(   
    num_wh=u'库房编号',
    location=u'库房位置',
    total_wh=u'总数',
    lock_wh=u'锁定数',
    unsold_wh=u'满库数',
    loss_wh=u'维护停用数',
    upate=u'更新时间'
    
    )
    column_editable_list = ['num_wh', 'location', 'total_wh','lock_wh','loss_wh','update']
    column_searchable_list = column_editable_list
   
    column_filters = column_editable_list
    form_overrides = {
        'password': PasswordField
    }

class CustomView(BaseView):
    @expose('/')
    def index(self):
        return self.render('admin/custom_index.html')

# Flask views
@app.route('/')
def index():
    return render_template('/index.html')

# Create admin
admin = flask_admin.Admin(
    app,
    '德数物联',
    base_template='my_master.html',
    template_mode='bootstrap3',
)

# Add model views
admin.add_view(MyModelView(Role, db.session, menu_icon_type='fa', menu_icon_value='fa-server', name=u'职能分配'))
admin.add_view(UserView(User, db.session, menu_icon_type='fa', menu_icon_value='fa-users', name=u"用户管理"))
admin.add_view(ProductView(Product, db.session, menu_icon_type='fa', menu_icon_value='fa-users', name=u"库存详情"))
admin.add_view(WHouseView(WHouse, db.session, menu_icon_type='fa', menu_icon_value='fa-users', name=u"库房管理"))

# define a context processor for merging flask-admin's template context into the
# flask-security views.
@security.context_processor
def security_context_processor():
    return dict(
        admin_base_template=admin.base_template,
        admin_view=admin.index_view,
        h=admin_helpers,
        get_url=url_for
    )

def build_sample_db():
    """
    Populate a small db with some example entries.
    """

    import string
    import random

    db.drop_all()
    db.create_all()

    with app.app_context():
        user_role = Role(name='user')
        super_user_role = Role(name='superuser')
        db.session.add(user_role)
        db.session.add(super_user_role)
        db.session.commit()

        test_user = user_datastore.create_user(
            first_name='Admin',
            email='admin',
            password=encrypt_password('admin'),
            roles=[user_role, super_user_role]
        )

        first_names = [
            'Harry', 'Amelia', 'Oliver', 'Jack', 'Isabella', 'Charlie', 'Sophie', 'Mia',
            'Jacob', 'Thomas', 'Emily', 'Lily', 'Ava', 'Isla', 'Alfie', 'Olivia', 'Jessica',
        ]
        last_names = [
            'Brown', 'Smith', 'Patel', 'Jones', 'Williams', 'Johnson', 'Taylor', 'Thomas',
            'Roberts', 'Khan', 'Lewis', 'Jackson', 'Clarke', 'James', 'Phillips', 'Wilson',
        ]

        for i in range(len(first_names)):
            tmp_email = first_names[i].lower() + "." + last_names[i].lower() + "@example.com"
            tmp_pass = ''.join(random.choice(string.ascii_lowercase + string.digits) for i in range(10))
            user_datastore.create_user(
                first_name=first_names[i],
                last_name=last_names[i],
                email=tmp_email,
                password=encrypt_password(tmp_pass),
                roles=[user_role, ]
            )
        db.session.commit()
    return

if __name__ == '__main__':
    with app.app_context():
        # Build a sample db on the fly, if one does not exist yet.
        app_dir = os.path.realpath(os.path.dirname(__file__))
        database_path = os.path.join(app_dir, app.config['DATABASE_FILE'])
        if not os.path.exists(database_path):
            build_sample_db()

        # Start app
        app.run(debug=True)
